<script setup>
import { ref, reactive, onMounted, watch, inject, computed } from 'vue'
import { globalStore } from '@/stores/global.js'
import {
  UploadFilled,
  Search,
  WarningFilled,
  ArrowUpBold,
  ArrowDownBold,
  Back,
  Right,
  CircleCheckFilled,
  Tools,
  Loading,
  Download,
  QuestionFilled,
  Close,
  RefreshLeft,
} from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

import CloseIcon from '@/components/icons/CloseIcon.vue'
import ModuleIcon from '@/components/icons/ModuleIcon.vue'
import CompressionIcon from '@/components/icons/CompressionIcon.vue'
import DownloadIcon from '@/components/icons/DownloadIcon.vue'
import ScriptFileIcon from '@/components/icons/ScriptFileIcon.vue'

const storeGlobal = globalStore()
const $http = inject('$http')


const packFormRef = ref(null)
const oneUploadRef = ref(null)
const state = reactive({
  packUpData: {},
  sessionId: null,
  showPacking: false,
  packingProgress: 0,
  packingDescription: '',
  allPackageName: [],
  // 步骤导航
  stepsList: [
    // type：check | uncheck | active
    { id: 1, name: '包信息配置', content: '设置升级包名称和描述文件', type: 'active', info: '请完成升级包基本信息配置，包括名称和描述文件。' },
    { id: 2, name: '选择拓扑', content: '选择一个需要打包的网元拓扑', type: 'uncheck', info: '请选择一个需要包含在本次升级包中的网元拓扑。' },
    { id: 3, name: '文件上传', content: '选择或上传模块脚本和升级文件', type: 'uncheck', info: '请为每个模块选择或上传脚本包，并上传其他升级文件。' },
    { id: 4, name: '打包生成', content: '生成带MD5校验的升级包', type: 'uncheck', info: '确认打包信息，点击"开始打包"生成包含MD5校验的升级包。' },
  ],
  stepsActive: 1,
  packUpModal: false,
  // 步骤一
  packForm: {
    packageName: '',
    descriptionFile: '',
  },
  packRules: {
    packageName: { required: true, message: '请输入升级包名称', trigger: 'blur' },
    descriptionFile: { required: true, message: '请上传版本描述文件', trigger: 'blur' },
  },
  // 步骤二
  searchNet: '',
  netElement: [],
  topologyFileForm: {
    sessionId: null,
    topologyId: null,
  },
  closeIconShow: false,
  // 步骤三
  uploadModuleForm: [],
  netElementData: {},
  scriptPackSelect: [],
  explainList: [],
  // 步骤四
  createMD5: true,
})

const infoStepsActive = computed(() => state.stepsList.find(i => i.id == state.stepsActive).info)
const allPackageNameLength = computed(() => state.allPackageName.length)
const getTopologyName = computed(() => {
  if (state.topologyFileForm.topologyId) {
    let data = state.netElement.find((i) => i.topologyId == state.topologyFileForm.topologyId)
    return data.netElementId + ' - ' + data.topologyName
  } else {
    return ''
  }
})

onMounted(() => {
  state.allPackageName = storeGlobal.scriptTypeList
  getTopologyList()
  getScriptPack()
})

watch(
  () => state.stepsActive,
  (newVal, oldVal) => {
    let oldData = state.stepsList.find((i) => i.id == oldVal)
    let data = state.stepsList.find((i) => i.id == newVal)
    data.type = 'active'
    if (newVal > oldVal) {
      oldData.type = 'check'
    } else {
      oldData.type = 'uncheck'
    }
    state.stepsList = state.stepsList.map((i) => {
      if (i.id == oldVal) {
        i = oldData
      }
      if (i.id == newVal) {
        i = data
      }
      return i
    })
  }
)

function getScriptPack() {
  $http('/api/script-package/list').then((res) => {
    state.scriptPackSelect = res
    state.scriptPackSelect.push({ packageId: 99999999, packageName: '-- 手动上传自定义脚本包 --' })
  })
}
function getTopologyList() {
  $http('/api/topology/list').then(res => {
    state.netElement = res
  })
}

const onSetpsChange = (key, setpsVal) => {
  // - minus  + add
  if (key == 'add') {
    if (setpsVal == 1) {
      packFormRef.value.validate((err, rules, val) => {
        if (err) {
          state.stepsActive = setpsVal + 1
        }else{
          ElMessage.error("请完善数据")
        }
      })
    } else if (setpsVal == 2) {
      if (state.topologyFileForm.topologyId) {
        let netElementData = state.netElement.find(
          (i) => i.topologyId == state.topologyFileForm.topologyId
        )
        state.netElementData = netElementData
        let arr = []
        netElementData.modules.forEach((i) => {
          arr.push({
            sessionId: null,
            moduleId: i.moduleId,
            packageId: null,
            scriptFiles: [],
            upgradeFiles: [],
            allPackageName: state.allPackageName.map((i) => {
              i['show'] = false
              return i
            }),
            ...i,
          })
        })
        state.uploadModuleForm = arr
        state.stepsActive = setpsVal + 1
      }else{
        ElMessage.error("请选择待打包拓扑")
      }
    } else if (setpsVal == 3) {
      if (state.uploadModuleForm.some((i) => i.allPackageName.every((j) => j.show))) {
        state.stepsActive = setpsVal + 1
      } else {
        ElMessage.error('模块脚本包检查结果未通过！')
      }
    } else {
      state.stepsActive = setpsVal + 1
    }
  } else {
    state.stepsActive = setpsVal - 1
  }
}

const showModal = (item) => {
  state.netElement = state.netElement.filter((i) => {
    if (i.topologyId == item.topologyId) {
      i.show = !i.show
    }
    return i
  })
}
const deleteTopolpgy = () => {
  state.topologyFileForm.topologyId = null
}
function oneUploadChange(file) {
  console.log(file, '=====');
  state.packForm.descriptionFile = file
}
function netElementMouse(type) {
  if (type == 'enter') {
    state.closeIconShow = true
  } else {
    state.closeIconShow = false
  }
}
function moduleUploadChange(file, item) {
  state.uploadModuleForm = state.uploadModuleForm.map((i) => {
    if (item.moduleId == i.moduleId) {
      // if (i.scriptFiles.length == 0 || i.scriptFiles.some((x) => x.name != file.name)) {
      i.scriptFiles = [file, ...i.scriptFiles]
      i['allPackageName'] = state.allPackageName.map((j) => {
        if (j.id.toUpperCase() == file.name.toUpperCase()) {
          j['show'] = true
        }
        return j
      })
      // } else {
      //   ElMessage.error('已上传该文件，请勿重复上传')
      // }
    }
    return i
  })
}
function moduleRemoveFile(file, item) {
  state.uploadModuleForm = state.uploadModuleForm.map((i) => {
    if (item.moduleId == i.moduleId) {
      i.scriptFiles = i.scriptFiles.filter((i) => i.name != file.name)
      i['allPackageName'] = state.allPackageName.map((j) => {
        if (j.id.toUpperCase() == file.name.toUpperCase()) {
          j['show'] = false
        }
        return j
      })
    }
    return i
  })
}

function othersUploadChange(file, item) {
  state.uploadModuleForm = state.uploadModuleForm.map((i) => {
    if (item.moduleId == i.moduleId) {
      i.upgradeFiles = [file, ...i.upgradeFiles]
    }
    return i
  })
}
function othersRemoveFile(file, item) {
  state.uploadModuleForm = state.uploadModuleForm.map((i) => {
    if (item.moduleId == i.moduleId) {
      i.upgradeFiles = i.upgradeFiles.filter((i) => i.name != file.name)
    }
    return i
  })
}

function scriptChange(val, item) {
  if (val != 99999999) {
    $http('/api/script/list', { params: { packageId: val } }).then((res) => {
      state.uploadModuleForm = state.uploadModuleForm.map((i) => {
        if (item.moduleId == i.moduleId) {
          i['allPackageName'] = res.map((j) => {
            return { id: j.scriptCode, name: j.scriptName, show: !!j.packageId }
          })
        }
        console.log(i, '数据')
        return i
      })
    })
  } else {
    state.uploadModuleForm = state.uploadModuleForm.map((i) => {
      if (item.moduleId == i.moduleId) {
        i['allPackageName'] = state.allPackageName.map((i) => {
          i['show'] = false
          return i
        })
      }
      return i
    })
  }
}
async function onPacking() {
  // 正在初始化打包目录
  // 正在创建网元拓扑文件夹
  // 正在上传模块脚本与升级文件
  // 正在生成校验信息
  // 准备完成
  state.showPacking = true
  state.packingDescription = '正在初始化打包目录...'
  state.packingProgress = 0

  // 3.1 包信息配置与打包目录初始化
  const formDataOne = new FormData()
  formDataOne.append('packageName', state.packForm.packageName)
  formDataOne.append(`descriptionFile`, state.packForm.descriptionFile.raw)
  $http
    .post('/api/package/init', formDataOne, {
      transformRequest: [], // 禁止数据转换
      headers: { 'Content-Type': 'multipart/form-data' },
    })
    .then((initRes) => {
      console.log(initRes, '初始化打包目录成功！')

      state.sessionId = initRes.sessionId
      state.packingDescription = '正在创建网元拓扑文件夹...'
      state.packingProgress = 20
      let paramsTwo = {
        sessionId: initRes.sessionId,
        topologyId: state.topologyFileForm.topologyId,
      }
      // 3.2 创建网元拓扑文件夹
      $http.post('/api/package/init/network/topology', paramsTwo).then((topologyRes) => {
        console.log(initRes, '创建网元拓扑文件夹成功！')
        state.packingDescription = '正在上传模块脚本与升级文件...'
        state.packingProgress = 40

        // 3.3 模块脚本与升级文件上传
        Promise.all(state.uploadModuleForm.map((i) => uploadFileScript(i))).then((values) => {
          state.packingDescription = '正在上传模块脚本与升级文件...'
          state.packingProgress = 60
          console.log(values, '模块脚本与升级文件上传成功！')

          // 3.4 脚本完整性校验（按当前打包文件夹）
          let paramsFour = {
            sessionId: initRes.sessionId,
            moduleIds: state.uploadModuleForm.map((i) => i.moduleId),
          }
          $http.post('/api/package/validate-scripts', paramsFour).then((checkRes) => {
            console.log(checkRes, '生成校验信息瓦城！')

            state.packingDescription = '准备完成，正在打包...'
            state.packingProgress = 80


            $http.post('/api/package/build', { sessionId: initRes.sessionId }).then((buildRes) => {
              console.log(buildRes, '打包完成！')

              state.packingProgress = 100
              state.packUpData = buildRes
            })
          })
        })
      })
    })
    .catch(err => {
      console.log(err, '数据');
    })
}
function uploadFileScript(item) {
  return new Promise((resolve, reject) => {
    console.log(item, '数据')
    const formData = new FormData()
    formData.append('sessionId', state.sessionId)
    formData.append(`moduleId`, item.moduleId)
    item.packageId != 99999999 && formData.append(`packageId`, item.packageId)
    item.scriptFiles.forEach((i) => {
      formData.append(`scriptFiles`, i.raw)
    })
    item.upgradeFiles.forEach((i) => {
      formData.append(`upgradeFiles`, i.raw)
    })
    $http
      .post('/api/package/upload-module', formData, {
        transformRequest: [], // 禁止数据转换
        headers: { 'Content-Type': 'multipart/form-data' },
      })
      .then((res) => resolve(res))
      .catch((err) => reject(err))
  })
}
async function downloadFilePack() {
  try {
    let data = await await $http('/api/package/download', {
      headers: { 'Content-Type': 'application/octet-stream' },
      responseType: 'blob',
      params: {fileName: state.packUpData.packageFileName}
    })

    // 创建下载链接
    const link = document.createElement('a')
    link.href = window.URL.createObjectURL(data)
    link.setAttribute('download', state.packUpData.packageFileName) // 设置文件名和格式
    document.body.appendChild(link)
    link.click()
    // 清理资源
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)
  } catch (error) {
    console.error('下载失败:', error)
  }
}
function onAgainPack(){
  let stateData = {
    packUpData: {},
    sessionId: null,
    showPacking: false,
    packingProgress: 0,
    packingDescription: '',
    allPackageName: [],
    // 步骤导航
    stepsList: [
      // type：check | uncheck | active
      { id: 1, name: '包信息配置', content: '设置升级包名称和描述文件', type: 'active' },
      { id: 2, name: '选择拓扑', content: '选择一个需要打包的网元拓扑', type: 'uncheck' },
      { id: 3, name: '文件上传', content: '选择或上传模块脚本和升级文件', type: 'uncheck' },
      { id: 4, name: '打包生成', content: '生成带MD5校验的升级包', type: 'uncheck' },
    ],
    stepsActive: 1,
    packUpModal: false,
    // 步骤一
    packForm: {
      packageName: '',
      descriptionFile: '',
    },
    packRules: {
      packageName: { required: true, message: '请输入升级包名称', trigger: 'blur' },
      descriptionFile: { required: true, message: '请上传版本描述文件', trigger: 'blur' },
    },
    // 步骤二
    searchNet: '',
    netElement: [],
    topologyFileForm: {
      sessionId: null,
      topologyId: null,
    },
    closeIconShow: false,
    // 步骤三
    uploadModuleForm: [],
    netElementData: {},
    scriptPackSelect: [],
    explainList: [],
    // 步骤四
    createMD5: true,
  }
  oneUploadRef.value.clearFiles()
  Object.keys(stateData).forEach(key => {
    state[key] = stateData[key]
  })
}
</script>
<template>
  <div class="content">
    <div class="w-full content-left w-2-3">
      <!-- 步骤导航 -->
      <div class="steps-box">
        <template v-for="item in state.stepsList" :key="item.id">
          <div class="steps-item">
            <div
              class="steps-num"
              :class="
                item.type == 'check'
                  ? 'steps-num-success'
                  : item.type == 'active'
                  ? 'steps-num-active'
                  : ''
              "
            >
              {{ item.id }}
            </div>
            <div>{{ item.name }}</div>
          </div>
          <div class="steps-line" v-show="item.id != 4"></div>
        </template>
      </div>
      <!-- 步骤一：包信息配置 -->
      <div class="package-info box-css" v-show="state.stepsActive == 1">
        <div class="box-title-txt" style="margin-bottom: 16px">升级包基本信息</div>
        <el-form
          :model="state.packForm"
          :rules="state.packRules"
          label-width="auto"
          ref="packFormRef"
        >
          <el-form-item label="升级包名称" prop="packageName">
            <el-input v-model="state.packForm.packageName" autocomplete="off" />
          </el-form-item>
          <el-form-item label="版本描述文件" prop="descriptionFile">
            <el-upload
              action=""
              class="upload-demo"
              ref="oneUploadRef"
              drag
              :auto-upload="false"
              :limit="1"
              :on-change="oneUploadChange"
            >
              <el-icon class="el-icon--upload"><upload-filled /></el-icon>
              <div class="el-upload__text">点击或拖拽文件至此处上传</div>
              <!-- <template #tip>
                <div class="el-upload__tip">支持 .txt / .md 格式，最大 10MB</div>
              </template> -->
            </el-upload>
          </el-form-item>
        </el-form>
        <div class="footer-btn">
          <el-button color="#165DFF" :dark="true" size="large" @click="onSetpsChange('add', 1)">
            <span style="margin-right: 6px">下一步：选择拓扑</span>
            <el-icon><Right /></el-icon>
          </el-button>
        </div>
      </div>
      <!-- 步骤二：选择拓扑 -->
      <div class="topology box-css" v-show="state.stepsActive == 2">
        <div class="topology-title">
          <span class="box-title-txt">选择待打包拓扑</span>
          <el-input v-model="state.searchNet" class="topology-search" placeholder="搜索网元...">
            <template #prefix>
              <el-icon class="el-input__icon"><search /></el-icon>
            </template>
          </el-input>
        </div>
        <div class="topology-tip">
          <el-icon><WarningFilled color="#165dff" /></el-icon>
          <span class="topology-tip-txt">每次打包只能选择一个网元拓扑</span>
        </div>
        <div class="net-list">
          <div class="net-item" v-for="item in state.netElement" :key="item.topologyId">
            <div class="net-item-title">
              <el-radio
                v-model="state.topologyFileForm.topologyId"
                :value="item.topologyId"
                size="large"
                :disabled="item.modules.length == 0"
                >网元拓扑
                {{
                  `[${item.netElementId}] - ${item.topologyName} ${
                    item.modules.length == 0 ? '（无模块）' : ''
                  }`
                }}
              </el-radio>
              <div class="net-item-switch" @click="showModal(item)">
                <span :style="item.modules.length == 0 ? 'color: #6b7280;' : ''">{{
                  item.modules.length == 0 ? '无模块' : item.show ? '收起模块' : '查看模块'
                }}</span>
                <el-icon v-show="item.modules.length != 0 && item.show"><ArrowUpBold /></el-icon>
                <el-icon v-show="item.modules.length != 0 && !item.show"
                  ><ArrowDownBold
                /></el-icon>
              </div>
            </div>
            <div class="net-modal-content" v-show="item.show">
              <div class="net-modal-item" v-for="(moduleItem, index) in item.modules" :key="index">
                <span>模块{{ index + 1 }}：</span>
                <span>{{ moduleItem.moduleName }}（升级顺序{{ moduleItem.upgradeOrder }}）</span>
              </div>
            </div>
          </div>
          <div v-show="state.netElement.length == 0">
            <el-empty description="暂无网元拓扑，请前往拓扑流程图管理中添加" />
          </div>
        </div>
        <div class="select-topology">
          <span class="select-topology-title">已选择拓扑</span>
          <span class="select-topology-none" v-show="!getTopologyName">未选择任何拓扑</span>
          <div class="select-topology-box" v-show="getTopologyName">
            <span>{{ getTopologyName }}</span>
            <CloseIcon
              class="close-icon"
              :fill="state.closeIconShow ? '#FF4D4F' : '#9CA3AF'"
              @mouseenter="netElementMouse('enter')"
              @mouseleave="netElementMouse('leave')"
              @click="deleteTopolpgy"
              width="14"
              height="14"
            />
          </div>
        </div>
        <div class="footer-btn">
          <el-button color="#165DFF" size="large" @click="onSetpsChange('add', 2)">
            <span style="margin-right: 6px">下一步：上传文件</span>
            <el-icon><Right /></el-icon>
          </el-button>
          <el-button size="large" :icon="Back" @click="onSetpsChange('minus', 2)">上一步</el-button>
        </div>
      </div>
      <!-- 步骤三：文件上传 -->
      <div class="file-upload box-css" v-show="state.stepsActive == 3">
        <div class="box-title-txt" style="margin-bottom: 16px">按模块上传升级文件</div>
        <div class="file-upload-tip">
          提示：请为每个模块上传所需的升级文件（包括软件包和配套脚本）
        </div>
        <div class="file-upload-explain">
          <div class="file-upload-explain-title">
            <el-icon><WarningFilled /></el-icon>
            <span>脚本文件必须包含以下所有内容（不能重复也不能缺少）</span>
          </div>
          <div class="file-upload-explain-list">
            <span class="script-required" v-for="item in state.allPackageName" :key="item.id">{{
              item.name
            }}</span>
          </div>
        </div>
        <div class="file-upload-content">
          <div class="file-upload-content-title">
            网元拓扑 [{{ state.netElementData.netElementId }}] -
            {{ state.netElementData.topologyName }}
          </div>
          <div
            class="file-upload-modal-item"
            v-for="item in state.uploadModuleForm"
            :key="item.moduleId"
          >
            <div class="file-upload-modal-item-title">
              <div class="file-upload-modal-item-left">
                <ModuleIcon width="14" height="14" />
                <span>模块：{{ item.moduleName }}</span>
                <span>(升级顺序：{{ item.upgradeOrder }})</span>
              </div>
              <span class="file-upload-modal-item-title-show">待上传</span>
            </div>
            <div class="file-upload-modal-from">
              <div class="file-upload-modal-from-label">模块脚本包 <span>*</span></div>
              <div class="file-upload-modal-from-content">
                <el-select
                  v-model="item.packageId"
                  @change="(val) => scriptChange(val, item)"
                  placeholder="请选择模块脚本包"
                  style="flex: 1"
                >
                  <el-option
                    v-for="scriptItem in state.scriptPackSelect"
                    :key="scriptItem.packageId"
                    :label="scriptItem.packageName"
                    :value="scriptItem.packageId"
                  />
                </el-select>
                <el-upload
                  v-show="item.packageId == 99999999"
                  action=""
                  class="upload-demo"
                  drag
                  multiple
                  :file-list="item.scriptFiles"
                  :limit="allPackageNameLength"
                  :auto-upload="false"
                  :on-change="(file) => moduleUploadChange(file, item)"
                  :before-remove="(file) => moduleRemoveFile(file, item)"
                >
                  <el-icon class="el-icon--upload"><upload-filled /></el-icon>
                  <div class="el-upload__text">点击或拖拽文件至此处上传（可多选）</div>
                  <!-- <template #tip>
                    <div class="el-upload__tip">支持 .txt / .md 格式，最大 10MB</div>
                  </template> -->
                </el-upload>
              </div>
              <div class="check-script">
                <div class="check-script-title">脚本检查结果：</div>
                <div class="file-upload-explain-list">
                  <span
                    :class="item.show ? 'script-required' : 'script-missing'"
                    v-for="item in item.allPackageName"
                    :key="item.id"
                    >{{ item.name }}</span
                  >
                </div>
              </div>
              <div class="file-upload-modal-from-label">
                其他升级文件（软件包等） <span>*</span>
              </div>
              <div class="file-upload-modal-from-content">
                <el-upload
                  action=""
                  class="upload-demo"
                  drag
                  multiple
                  :auto-upload="false"
                  :file-list="item.upgradeFiles"
                  :on-change="(file) => othersUploadChange(file, item)"
                  :before-remove="(file) => othersRemoveFile(file, item)"
                >
                  <el-icon class="el-icon--upload"><upload-filled /></el-icon>
                  <div class="el-upload__text">点击或拖拽文件至此处上传（可多选）</div>
                  <!-- <template #tip>
                    <div class="el-upload__tip">支持 .zip / .tar / .gz / .jar 格式</div>
                  </template> -->
                </el-upload>
              </div>
            </div>
          </div>
        </div>
        <div class="footer-btn">
          <el-button color="#165DFF" size="large" @click="onSetpsChange('add', 3)">
            <span style="margin-right: 6px">下一步：上传文件</span>
            <el-icon><Right /></el-icon>
          </el-button>
          <el-button size="large" :icon="Back" @click="onSetpsChange('minus', 3)">上一步</el-button>
        </div>
      </div>
      <!-- 步骤四：打包生成 -->
      <div class="pack-up box-css" v-show="state.stepsActive == 4">
        <div class="box-title-txt" style="margin-bottom: 16px">打包配置确认</div>
        <div class="pack-up-check">
          <div class="pack-up-check-title">
            <el-icon class="pack-up-check-icon"><CircleCheckFilled /></el-icon>
            <!-- <el-icon><WarningFilled /></el-icon>
            <el-icon><Loading /></el-icon> -->
            <span>脚本完整性检查通过</span>
          </div>
          <div class="pack-up-check-remark">所有必需的脚本文件均已包含且无重复</div>
        </div>
        <div class="pack-up-packinfo">
          <div class="pack-up-packinfo-title">升级包信息</div>
          <div class="pack-up-packinfo-content">
            <div class="pack-up-packinfo-item">
              <span>包名称：</span>
              <span>{{ state.packForm.packageName }}</span>
            </div>
            <div class="pack-up-packinfo-item">
              <span>版本描述：</span>
              <span>{{ state.packForm.descriptionFile.name }}</span>
            </div>
            <div class="pack-up-packinfo-item">
              <span>包含拓扑：</span>
              <span
                >{{ state.netElementData.netElementId }} -
                {{ state.netElementData.topologyName }}</span
              >
            </div>
            <div class="pack-up-packinfo-item">
              <span>总模块数：</span>
              <span>{{ state.uploadModuleForm.length }}</span>
            </div>
            <div class="pack-up-packinfo-item">
              <span>打包格式：</span>
              <span>ZIP 格式</span>
            </div>
          </div>
        </div>
        <div class="pack-up-options">
          <div class="pack-up-options-title">打包选项</div>
          <div class="pack-up-options-content">
            <div class="pack-up-options-item">
              <el-checkbox v-model="state.createMD5" disabled></el-checkbox>
              <span>生成文件校验和（MD5）</span>
              <span class="pack-up-options-item-info">(必填)</span>
            </div>
          </div>
        </div>
        <div class="pack-up-progress" v-show="state.showPacking == false && state.packingProgress != 100 && state.packingProgress != 0">
          <div class="pack-up-progress-top">正在打包...</div>
          <el-progress class="pack-up-progress-progress" :percentage="state.packingProgress" color="#165DFF" />
          <div class="pack-up-progress-info gray text-xs">{{ state.packingDescription }}</div>
        </div>
        <div class="pack-up-success" v-show="state.packingProgress == 100">
          <el-icon class="pack-up-success-icon"><CircleCheckFilled /></el-icon>
          <div class="pack-up-success-content">
            <div class="pack-up-success-title">打包完成！</div>
            <div class="pack-up-success-remark">
              升级包已成功生成，包含MD5校验信息，可下载后发送给运维人员进行升级操作。
            </div>
            <div class="pack-up-success-file">
              <CompressionIcon class="mar-8" width="14" height="14" />
              <span class="mar-12">{{ state.packUpData.packageFileName }}</span>
              <span class="cursor-pointer" @click="downloadFilePack">
                <DownloadIcon width="14" height="14" />
                <span class="active-color">下载</span>
              </span>
            </div>
            <div class="pack-up-success-MD5 none-color text-xs">
              MD5校验值：{{ state.packUpData.md5 }}
            </div>
          </div>
        </div>
        <div class="footer-btn">
          <el-button color="#165DFF" size="large" :icon="Tools" @click="onPacking">
            开始打包
          </el-button>
          <el-button
            size="large"
            :disabled="state.showPacking"
            :icon="Back"
            @click="onSetpsChange('minus', 4)"
            >上一步</el-button
          >
        </div>
      </div>
    </div>
    <div class="w-full content-right w-1-3">
      <div class="pack-up-process box-css">
        <div class="pack-up-process-title">打包流程</div>
        <div class="pack-up-process-content">
          <div class="pack-up-process-list">
            <template v-for="(item, index) in state.stepsList" :key="item.id">
              <div
                class="pack-up-process-item"
                :class="
                  item.type == 'active'
                    ? 'pack-up-process-item-active'
                    : item.type == 'check'
                    ? 'pack-up-process-item-success'
                    : ''
                "
              >
                <div class="pack-up-process-item-left">{{ index + 1 }}</div>
                <div class="pack-up-process-item-right">
                  <span class="text-sm">{{ item.name }}</span>
                  <span class="text-xs">{{ item.content }}</span>
                </div>
              </div>
              <div class="pack-up-process-line" v-if="index != 3">
                <div
                  class="pack-up-process-line-active"
                  :style="{ width: item.id < state.stepsActive ? '100%' : '0' }"
                ></div>
              </div>
            </template>
          </div>
          <div class="pack-up-process-info">
            <div class="mar-bottom text-sm">当前状态</div>
            <div class="text-sm">{{infoStepsActive}}</div>
            <div class="pack-up-process-tip text-sm" @click="state.packUpModal = true">
              <el-icon class="pack-up-process-icon"><QuestionFilled /></el-icon>
              <span class="mar-left">查看帮助</span>
            </div>
          </div>
          <div class="mar-top" v-show="state.showPacking">
            <el-button color="#165DFF" size="large" @click="onAgainPack">
              <span style="margin-right: 6px">重新打包</span>
              <el-icon><RefreshLeft /></el-icon>
            </el-button>
          </div>
        </div>
        <el-dialog v-model="state.packUpModal" width="500" title="打包流程帮助" align-center>
          <div class="pack-up-modal-title">
            <el-icon><WarningFilled /></el-icon>
            <span class="mar-left">打包流程说明</span>
          </div>
          <div class="pack-up-modal-info text-sm">
            该工具帮助您将网元拓扑的模块文件打包为一个升级包，包含必要的MD5校验信息。
          </div>
          <div class="pack-up-modal-label">步骤1：包信息配置</div>
          <div class="pack-up-modal-val text-sm">
            设置升级包的基本信息，包括名称和版本描述文件。
          </div>
          <div class="pack-up-modal-label">步骤2：选择拓扑</div>
          <div class="pack-up-modal-val text-sm">
            每次打包只能选择一个网元拓扑，系统会显示该拓扑包含的所有模块。
          </div>
          <div class="pack-up-modal-label">步骤3：文件上传</div>
          <div class="pack-up-modal-val text-sm">
            为每个模块选择或上传脚本包，并上传其他升级文件（软件包等）。
          </div>
          <div class="pack-up-modal-val text-sm">
            脚本包必须包含所有必需的脚本文件，系统会自动进行完整性检查。
          </div>
          <div class="pack-up-modal-label">步骤4：打包生成</div>
          <div class="pack-up-modal-val text-sm">
            系统会自动生成包含所有文件和MD5校验信息的升级包，您可以下载并使用。
          </div>
          <template #footer>
            <div class="dialog-footer">
              <el-button color="#165DFF" @click="state.packUpModal = false">我知道了</el-button>
            </div>
          </template>
        </el-dialog>
      </div>
    </div>
  </div>
</template>
<style scoped lang="less">
.mar-left {
  margin-left: 4px;
}
.mar-top{
  margin-top: 16px;
}
.content {
  display: flex;
  flex-flow: row wrap;
  gap: 24px;
  .content-right {
    .pack-up-process {
      padding: 0;
      .pack-up-modal-label {
        font-size: 16px;
        color: #333;
        margin: 16px 0 0;
      }
      .pack-up-modal-title {
        color: #165dff;
        display: flex;
        font-size: 16px;
        align-items: center;
        margin: 0 0 8px;
      }
      .pack-up-process-content {
        padding: 24px;
        .pack-up-process-info {
          padding: 16px;
          background-color: #f2f3f5;
          border-radius: 8px;
          margin-top: 32px;
          .mar-bottom {
            margin-bottom: 8px;
          }
          .mar-left {
            margin-left: 4px;
          }
          .pack-up-process-tip {
            color: #165dff;
            display: flex;
            align-items: center;
            margin-top: 16px;
            cursor: pointer;
            .pack-up-process-icon {
              font-size: 16px;
            }
          }
        }
        .pack-up-process-list {
          display: flex;
          flex-direction: column;
          align-items: center;
          .pack-up-process-line {
            width: 25%;
            margin: 0 auto;
            height: 4px;
            background-color: #c9cdd4;
            margin: 0 0 8px;
            .pack-up-process-line-active {
              transition-property: all;
              transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
              transition-duration: 300ms;
              background-color: #165dff;
              width: 0;
              height: 100%;
            }
          }
          .pack-up-process-item-success {
            border-color: #52c41a !important;
            .pack-up-process-item-left {
              background-color: #52c41a !important;
              border-width: 0 !important;
              line-height: 32px !important;
              color: #ffffff !important;
            }
            .pack-up-process-item-right {
              span:nth-child(1) {
                color: #333 !important;
              }
            }
          }
          .pack-up-process-item-active {
            border-color: #165dff !important;
            transform: scale(1.05);
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
            background-color: rgba(22, 93, 255, 0.1);
            .pack-up-process-item-left {
              background-color: #165dff !important;
              border-width: 0 !important;
              line-height: 32px !important;
              color: #ffffff !important;
            }
            .pack-up-process-item-right {
              span:nth-child(1) {
                color: #333 !important;
              }
            }
          }
          .pack-up-process-item {
            width: 100%;
            margin: 0 0 8px;
            padding: 12px;
            border-radius: 8px;
            border: 2px solid #c9cdd4;
            transition-property: all;
            transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
            transition-duration: 300ms;
            display: flex;
            align-items: center;
            .pack-up-process-item-right {
              margin-left: 12px;
              span {
                display: block;
              }
              span:nth-child(1) {
                color: #86909c;
              }
              span:nth-child(2) {
                color: #86909c;
              }
            }
            .pack-up-process-item-left {
              width: 32px;
              height: 32px;
              line-height: 28px;
              border-radius: 9999px;
              text-align: center;
              border: 2px solid #c9cdd4;
              background-color: #fff;
              color: #86909c;
            }
          }
        }
      }
      .pack-up-process-title {
        background-color: #f9fafb;
        padding: 16px;
        border-bottom: 1px solid #e5e7eb;
        border-radius: 12px 12px 0 0;
      }
    }
  }
  .content-left {
    .pack-up {
      .pack-up-progress{
        margin: 0 0 16px;
      }
      .pack-up-success {
        background-color: rgba(250, 173, 20, 0.1);
        border: 1px solid rgba(250, 173, 20, 0.3);
        border-radius: 8px;
        padding: 12px;
        margin-bottom: 24px;
        display: flex;
        flex-flow: row;
        .pack-up-success-content {
          .pack-up-success-MD5 {
            padding: 8px;
            background-color: #f2f3f5;
            border-radius: 4px;
            margin: 12px 0 0;
          }
          .pack-up-success-file {
            display: flex;
            align-items: center;
            margin: 12px 0 0;
            .mar-12 {
              margin-right: 12px;
            }
            .mar-8 {
              margin-right: 8px;
            }
          }
          .pack-up-success-remark {
            color: #374151;
            font-size: 14px;
            line-height: 20px;
            margin: 4px 0 0;
          }
          .pack-up-success-title {
            color: #52c41a;
          }
        }
        .pack-up-success-icon {
          font-size: 20px;
          line-height: 28px;
          color: #52c41a;
          margin: 2px 12px 0 0;
        }
      }
      .pack-up-options {
        border: 1px solid #e5e7eb;
        border-radius: 8px;
        margin: 0 0 24px;
        .pack-up-options-content {
          padding: 16px;
        }
        .pack-up-options-item {
          display: flex;
          align-items: center;
          font-size: 14px;
          .pack-up-options-item-info {
            font-size: 12px;
            line-height: 16px;
            color: #86909c;
          }
        }
        .pack-up-options-title {
          padding: 8px 16px;
          background-color: #f2f3f5;
          border-radius: 8px 8px 0 0;
        }
      }
      .pack-up-packinfo {
        border: 1px solid #e5e7eb;
        border-radius: 8px;
        margin: 0 0 24px;
        .pack-up-packinfo-content {
          padding: 16px;
          .pack-up-packinfo-item {
            display: grid;
            gap: 8px;
            grid-template-columns: repeat(3, minmax(0, 1fr));
            font-size: 14px;
            line-height: 20px;
            margin: 8px 0 0;
            span:nth-child(1) {
              color: #86909c;
            }
          }
        }
        .pack-up-packinfo-title {
          padding: 8px 16px;
          background-color: #f2f3f5;
          border-radius: 8px 8px 0 0;
        }
      }
      .pack-up-check {
        background-color: rgba(250, 173, 20, 0.1);
        border: 1px solid rgba(250, 173, 20, 0.3);
        border-radius: 8px;
        padding: 12px;
        margin-bottom: 24px;
        .pack-up-check-remark {
          color: #86909c;
          font-size: 14px;
          line-height: 20px;
          margin: 4px 0 0;
        }
        .pack-up-check-title {
          display: flex;
          align-items: center;
          .pack-up-check-icon {
            color: #52c41a;
          }
          span {
            margin-left: 8px;
          }
        }
      }
    }
    .file-upload {
      .file-upload-content {
        border: 1px solid #e5e7eb;
        border-radius: 8px;
        margin: 0 0 24px;
        .file-upload-modal-item {
          padding: 16px 16px 0;
          .file-upload-modal-from {
            .check-script {
              margin: 8px 0 16px;
              .check-script-title {
                font-size: 12px;
              }
            }
            .file-upload-modal-from-content {
              display: flex;
              flex-direction: column;
              align-items: center;
              gap: 12px;
            }
            .file-upload-modal-from-label {
              color: #374151;
              font-size: 14px;
              line-height: 20px;
              margin: 0 0 4px;
              span {
                color: #ff4d4f;
              }
            }
          }
          .file-upload-modal-item-title {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin: 0 0 4px;
            .file-upload-modal-item-title-show {
              padding: 4px 8px;
              font-size: 12px;
              line-height: 16px;
              background-color: #f2f3f5;
              border-radius: 9999px;
            }
            .file-upload-modal-item-left {
              display: flex;
              align-items: center;
              span:nth-child(2) {
                margin: 0 6px;
              }
              span:nth-child(3) {
                color: #86909c;
                font-size: 14px;
              }
            }
          }
        }
        .file-upload-content-title {
          padding: 8px 16px;
          border-radius: 8px 8px 0 0;
          background-color: #f2f3f5;
        }
      }
      .file-upload-explain-list {
        display: flex;
        align-items: center;
        flex-flow: wrap;
        gap: 4px;
        .script-required {
          margin-top: 8px;
          border-radius: 4px;
          background-color: rgba(22, 93, 255, 0.1);
          padding: 2px 6px;
          font-size: 12px;
          line-height: 16px;
          color: #165dff;
        }
        .script-missing {
          margin-top: 8px;
          border-radius: 4px;
          background-color: rgba(255, 77, 79, 0.1);
          padding: 2px 6px;
          font-size: 12px;
          line-height: 16px;
          color: rgba(255, 77, 79, 1);
        }
      }
      .file-upload-explain {
        background-color: rgba(250, 173, 20, 0.1);
        border: 1px solid rgba(250, 173, 20, 0.3);
        border-radius: 8px;
        padding: 12px;
        margin-bottom: 24px;
        .file-upload-explain-title {
          color: #faad14;
          font-size: 14px;
          line-height: 20px;
          display: flex;
          align-items: center;
          span {
            margin-left: 8px;
          }
        }
      }
      .file-upload-tip {
        color: #86909c;
        font-size: 14px;
        line-height: 20px;
        margin-bottom: 16px;
      }
    }
    .topology {
      .select-topology {
        background-color: #f2f3f5;
        border-radius: 8px;
        padding: 16px;
        display: flex;
        flex-flow: column;
        margin-bottom: 24px;
        .select-topology-box {
          padding: 6px 12px;
          background-color: #fff;
          border-radius: 4px;
          border: 1px solid #e5e7eb;
          width: fit-content;
          display: flex;
          align-items: center;
          .close-icon {
            margin-left: 4px;
            cursor: pointer;
          }
        }
        .select-topology-none {
          color: #86909c;
          font-size: 14px;
          line-height: 20px;
          font-style: italic;
        }
        .select-topology-title {
          font-size: 14px;
          line-height: 20px;
          margin: 0 0 8px;
        }
        span {
          display: inline-block;
        }
      }
      .net-list {
        display: flex;
        flex-direction: column;
        margin: 0 0 24px;
        .net-item {
          padding: 6px 12px;
          border: 1px solid #e5e7eb;
          border-radius: 8px;
          width: 100%;
          margin-top: 8px;
          .net-modal-content {
            margin: 8px 0 0 24px;
            padding-left: 12px;
            border-left: 2px solid #f2f3f5;
            font-size: 14px;
            line-height: 26px;
            span:nth-child(1) {
              color: #86909c;
            }
            span:nth-child(2) {
              color: #333;
            }
          }
          .net-item-title {
            display: flex;
            justify-content: space-between;
            align-items: center;
            --el-radio-input-border-color-hover: rgba(22, 93, 255, 1);
            .net-item-switch {
              font-size: 14px;
              color: rgba(22, 93, 255, 1);
              cursor: pointer;
              span {
                margin: 0 6px 0 0;
              }
            }
          }
        }
        .net-item:hover {
          border-color: rgba(22, 93, 255, 1);
        }
      }
      .topology-tip {
        background-color: rgba(22, 93, 255, 0.05);
        border: 1px solid rgba(22, 93, 255, 0.5);
        border-radius: 8px;
        padding: 12px;
        color: #165dff;
        display: flex;
        align-items: center;
        .topology-tip-txt {
          margin: 0 0 0 10px;
        }
      }
      .topology-title {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin: 0 0 16px;
        .topology-search {
          width: 192px;
          --el-input-border-radius: 8px;
        }
      }
    }
    .steps-box {
      display: flex;
      flex-flow: wrap row;
      justify-content: space-between;
      align-items: center;
      .steps-item {
        width: 25%;
        margin-bottom: 16px;
        text-align: center;
        .steps-num-success {
          background-color: #52c41a !important;
          color: #ffffff !important;
          border: none !important;
        }
        .steps-num-active {
          background-color: #165dff !important;
          color: #ffffff !important;
          border: none !important;
        }
        .steps-num {
          width: 40px;
          height: 40px;
          color: #86909c;
          border: 2px solid #c9cdd4;
          background-color: #ffffff;
          border-radius: 99999px;
          text-align: center;
          line-height: 36px;
          box-sizing: border-box;
        }
        div {
          margin: 0 auto;
        }
      }
      .steps-line {
        width: 25%;
        height: 4px;
        background-color: #c9cdd4;
      }
    }
    .upload-demo {
      width: 100%;
    }
  }

  .box-css {
    border-radius: 12px;
    padding: 24px;
    border: 1px solid #e5e7eb;
    background-color: #ffffff;
    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);
    margin: 16px 0 0;
    .box-title-txt {
      font-size: 18px;
      font-weight: 800;
    }
    .footer-btn {
      display: flex;
      justify-content: space-between;
      align-items: center;
      flex-direction: row-reverse;
    }
  }
}
.active-color {
  color: #165dff;
}
.none-color {
  color: #86909c;
}
</style>
<style>
.el-radio.el-radio--large .el-radio__label {
  font-size: 16px;
}
</style>
